#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#define DEFAULT_FILE_LINE_NUMBER 2048

char **read_file(const char *filename, int buf_size);
void print_data(char **data);
void free_data(char **data);

int main(void) {
    const char *filename = "/home/chongzi/go/t.ini";
    char **data = read_file(filename, 1024);
    if (data == NULL) {
        printf("read file error: %d\n", errno);
        return EXIT_FAILURE;
    }
    print_data(data);
    free_data(data);
    return EXIT_SUCCESS;
}

/**
 * read file
 *
 * @param const char * filename
 * @param int          buf_size 读读
 */
char **read_file(const char *filename, int buf_size) {
    FILE *fp = fopen(filename, "r");
    if (fp == NULL) {
        printf("open %s file error:%d\n", filename, errno);
        return NULL;
    }
    if (buf_size == 0) {
        puts("buf size error");
        exit(EXIT_FAILURE);
    }

    char read_buf[buf_size];
    char **data = (char **) malloc(sizeof(char *) * DEFAULT_FILE_LINE_NUMBER);
    if (data == NULL) {
        puts("allow data pointer memory error");
        fclose(fp);
        exit(EXIT_FAILURE);
    }
    int i = 0;
    char *line_ptr;
    int nchar = 0;
    int read_buf_len = 0;
    while (!feof(fp)) {
        if (fgets(read_buf, buf_size, fp) != NULL) {
            read_buf_len = strlen(read_buf);
            if (data[i] == NULL) {
                data[i] = (char *)malloc(buf_size);
                if (data[i] == NULL) {
                    free_data(data);
                    fclose(fp);
                    puts("realloc memory error");
                    exit(EXIT_FAILURE);
                }
            } else if(nchar + read_buf_len >= buf_size) {
                data[i] = (char *)realloc(data[i], (nchar + read_buf_len) * 2);
                if (data[i] == NULL) {
                    free_data(data);
                    fclose(fp);
                    puts("realloc memory error");
                    exit(EXIT_FAILURE);
                }
            }
            line_ptr = data[i] + nchar;
            memcpy(line_ptr, read_buf, read_buf_len);
            nchar += read_buf_len;
            if (strchr(read_buf, '\n') != NULL) {
                i++;
                nchar = 0;
            }
        }
    }
    clearerr(fp);
    fclose(fp);
    return data;
}

/**
 * print data
 *
 * @param char ** data
 */
void print_data(char **data) {
    if (data != NULL) {
        int i;
        for (i = 0; data[i] != NULL; i++) {
            puts(data[i]);
        }
    }
}

/**
 * 释释释释 free data memory
 *
 * @param char ** data
 * @param int size
 */
void free_data(char **data) {
    if (data != NULL) {
        int i;
        for (i = 0; data[i] != NULL; i++) {
            free(data[i]);
        }
        free(data);
        data = NULL;
    }
}
